home *** CD-ROM | disk | FTP | other *** search
/ QRZ! Ham Radio 1 / QRZ Ham Radio Callsign Database - December 1993.iso / ucsd / packet / tcpip / sys5 / iscwmpst.z / iscwmpst / tcp / src / sys5login.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-10-10  |  14.2 KB  |  586 lines

  1. /* @(#) $Header: login.c,v 1.10 91/02/24 20:17:12 deyke Exp $ */
  2. /* OLE '91 */
  3. #include <sys/types.h>
  4.  
  5. #include <stdio.h>      /* must be before pwd.h */
  6.  
  7. #include <ctype.h>
  8. #include <errno.h>
  9. #include <fcntl.h>
  10. #include <pwd.h>
  11. #include <signal.h>
  12. #include <stdlib.h>
  13. #include <string.h>
  14. #include <time.h>
  15. #ifdef SPASSWD
  16. #include <shadow.h>
  17. #endif
  18. #include <sys/stat.h>
  19. #include <termio.h>
  20. #include <unistd.h>
  21. #include <utmp.h>
  22.  
  23. #include "global.h"
  24. #include "mbuf.h"
  25. #include "timer.h"
  26. #include "hpux.h"
  27. #include "telnet.h"
  28. #include "login.h"
  29.  
  30. extern struct utmp *getutent();
  31. extern struct utmp *getutid();
  32. extern void endutent();
  33. extern void pututline();
  34.  
  35. #define MASTERPREFIX        "/dev/pty"
  36. #define SLAVEPREFIX         "/dev/tty"
  37.  
  38. #define PASSWDFILE          "/etc/passwd"
  39. #define PWLOCKFILE          "/etc/ptmp"
  40.  
  41. #define DEFAULTUSER         "guest"
  42. #define FIRSTUID            400
  43. #define MAXUID              4095
  44. #define GID                 400
  45. #define HOMEDIRPARENTPARENT "/users/funk"
  46.  
  47. /* login server control block */
  48.  
  49. struct login_cb {
  50.   int  pty;                     /* pty file descriptor */
  51.   int  num;                     /* pty number */
  52.   char  id[4];                  /* pty id (last 2 chars) */
  53.   int  pid;                     /* process id of login process */
  54.   char  inpbuf[512];            /* pty read buffer */
  55.   char  *inpptr;                /* pty read buffer pointer */
  56.   int  inpcnt;                  /* pty read buffer count */
  57.   struct mbuf *sndq;            /* pty send queue */
  58.   int  lastchr;                 /* last chr fetched from send queue */
  59.   int  linelen;                 /* counter for automatic line break */
  60.   char  outbuf[256];            /* pty write buffer */
  61.   char  *outptr;                /* pty write buffer pointer */
  62.   int  outcnt;                  /* pty write buffer count */
  63.   void (*readfnc) __ARGS((void *fncarg));
  64.                 /* func to call if pty is readable */
  65.   void (*closefnc) __ARGS((void *fncarg));
  66.                 /* func to call if pty gets closed */
  67.   void  *fncarg;                /* argument for readfnc and closefnc */
  68.   int  telnet;                  /* telnet mode */
  69.   int  state;                   /* telnet state */
  70.   char  option[NOPTIONS+1];     /* telnet options */
  71. };
  72.  
  73. static char  pty_inuse[256];
  74.  
  75. static int find_pty __ARGS((int *numptr, char *slave));
  76. static void restore_pty __ARGS((char *id));
  77. static void write_log_header __ARGS((int fd, char *user, char *protocol));
  78. static int do_telnet __ARGS((struct login_cb *tp, int chr));
  79. static void write_pty __ARGS((struct login_cb *tp));
  80. static void excp_handler __ARGS((struct login_cb *tp));
  81.  
  82. /*---------------------------------------------------------------------------*/
  83.  
  84. #define pty_name(name, prefix, num) \
  85.   sprintf(name, "%s%c%x", prefix, 'p' + (num >> 4), num & 0xf)
  86.  
  87. /*---------------------------------------------------------------------------*/
  88.  
  89. static int  find_pty(numptr, slave)
  90. int  *numptr;
  91. char  *slave;
  92. {
  93.  
  94.   char  master[80];
  95.   int  fd, num;
  96.  
  97.   for (num = 0; ; num++)
  98.     if (!pty_inuse[num]) {
  99.       pty_name(master, MASTERPREFIX, num);
  100.       if ((fd = open(master, O_RDWR | O_NDELAY, 0600)) >= 0) { 
  101.     pty_inuse[num] = 1;
  102.     *numptr = num;
  103.     pty_name(slave, SLAVEPREFIX, num);
  104.     return fd;
  105.       }
  106.       if (errno != EBUSY) return (-1);
  107.       pty_inuse[num] = 1;
  108.     }
  109. }
  110.  
  111. /*---------------------------------------------------------------------------*/
  112.  
  113. static void restore_pty(id)
  114. char  *id;
  115. {
  116.   char  filename[80];
  117.  
  118.   sprintf(filename, "%s%s", MASTERPREFIX, id);
  119.   chown(filename, 0, 0);
  120.   chmod(filename, 0666);
  121.   sprintf(filename, "%s%s", SLAVEPREFIX, id);
  122.   chown(filename, 0, 0);
  123.   chmod(filename, 0666);
  124. }
  125.  
  126. /*---------------------------------------------------------------------------*/
  127.  
  128. void fixutmpfile()
  129. {
  130.   register struct utmp *up;
  131.  
  132.   while (up = getutent())
  133.     if (up->ut_type == USER_PROCESS && kill(up->ut_pid, 0)) {
  134.       restore_pty(up->ut_id);
  135.       up->ut_user[0] = '\0';
  136.       up->ut_type = DEAD_PROCESS;
  137.       up->ut_exit.e_termination = 0;
  138.       up->ut_exit.e_exit = 0;
  139.       up->ut_time = secclock();
  140.       pututline(up);
  141.     }
  142.   endutent();
  143. }
  144.  
  145. /*---------------------------------------------------------------------------*/
  146.  
  147. struct passwd *getpasswdentry(name, create)
  148. char  *name;
  149. int  create;
  150. {
  151.  
  152.   FILE * fp;
  153.   char  *cp;
  154.   char  bitmap[MAXUID+1];
  155.   char  homedir[80];
  156.   char  homedirparent[80];
  157.   char  username[128];
  158.   int  fd;
  159.   int  uid;
  160.   struct passwd *pw;
  161. #ifdef SPASSWD
  162.   struct spwd *sw;
  163. #endif
  164.  
  165.   /* Fix user name */
  166.  
  167.   for (cp = username; isalnum(uchar(*name)); *cp++ = tolower(uchar(*name++))) ;
  168.   *cp = '\0';
  169.   if (!isalpha(uchar(*username)) || strlen(username) > 8)
  170.     strcpy(username, DEFAULTUSER);
  171.  
  172.   /* Search existing passwd entry */
  173.  
  174.   while ((pw = getpwent()) && strcmp(username, pw->pw_name)) ;
  175.   endpwent();
  176. #ifdef SPASSWD
  177.   while ((sw = getspent()) && strcmp(username, sw->sp_namp)) ;
  178.   endspent();
  179.   if (sw) 
  180.   pw->pw_passwd = sw->sp_pwdp;
  181. #endif
  182.   if (pw) return pw;
  183.   if (!create) return 0;
  184.  
  185.   /* Find free user id */
  186.  
  187.   if ((fd = open(PWLOCKFILE, O_WRONLY | O_CREAT | O_EXCL, 0644)) < 0) return 0;
  188.   close(fd);
  189.   memset(bitmap, 0, sizeof(bitmap));
  190.   while (pw = getpwent()) {
  191.     if (!strcmp(username, pw->pw_name)) break;
  192.     if (pw->pw_uid <= MAXUID) bitmap[pw->pw_uid] = 1;
  193.   }
  194.   endpwent();
  195.   if (pw) {
  196.     unlink(PWLOCKFILE);
  197.     return pw;
  198.   }
  199.   for (uid = FIRSTUID; uid <= MAXUID && bitmap[uid]; uid++) ;
  200.   if (uid > MAXUID) {
  201.     unlink(PWLOCKFILE);
  202.     return 0;
  203.   }
  204.  
  205.   /* Add user to passwd file */
  206.  
  207.   sprintf(homedirparent, "%s/%.3s...", HOMEDIRPARENTPARENT, username);
  208.   sprintf(homedir, "%s/%s", homedirparent, username);
  209.   if (!(fp = fopen(PASSWDFILE, "a"))) {
  210.     unlink(PWLOCKFILE);
  211.     return 0;
  212.   }
  213. #ifdef SPASSWD
  214.   fprintf(fp, "%s:x:%d:%d::%s:/bin/sh\n", username, uid, GID, homedir);
  215. #else
  216.   fprintf(fp, "%s:,./:%d:%d::%s:/bin/sh\n", username, uid, GID, homedir);
  217. #endif
  218.   fclose(fp);
  219.   pw = getpwuid(uid);
  220.   endpwent();
  221.   unlink(PWLOCKFILE);
  222.  
  223. #ifdef SPASSWD
  224.   if ((fd = open(SHADTEMP, O_WRONLY | O_CREAT | O_EXCL, 0644)) < 0) return 0;
  225.   close(fd);
  226.  
  227.   /* Add user to Shadow file */
  228.  
  229.    if (!(fp = fopen(SHADOW, "a"))) {
  230.    unlink(SHADTEMP);
  231.    return 0;
  232.    }
  233.    
  234.   fprintf(fp, "%s::%d:%d:%d\n", username, 7676,10000,10000); /** 7676 = expire time ?! **/
  235.   fclose(fp);
  236.   unlink(SHADTEMP);
  237.   pw->pw_passwd= "\0";  /** to avoid another getspent call **/ 
  238.  
  239. #endif /* SPASSWD */
  240.  
  241.   /* Create home directory */
  242.  
  243.   mkdir(homedirparent, 0755);
  244.   mkdir(homedir, 0755);
  245.   chown(homedir, uid, GID);
  246.   return pw;
  247. }
  248.  
  249. /*---------------------------------------------------------------------------*/
  250.  
  251. static void write_log_header(fd, user, protocol)
  252. int  fd;
  253. char  *user, *protocol;
  254. {
  255.  
  256.   char  buf[1024];
  257.   struct tm *tm;
  258.  
  259.   tm = localtime((long *) &Secclock);
  260.   sprintf(buf,
  261.       "%s at %2d-%.3s-%02d %2d:%02d:%02d by %s\n",
  262.       protocol,
  263.       tm->tm_mday,
  264.       "JanFebMarAprMayJunJulAugSepOctNovDec" + 3 * tm->tm_mon,
  265.       tm->tm_year % 100,
  266.       tm->tm_hour,
  267.       tm->tm_min,
  268.       tm->tm_sec,
  269.       user);
  270.   write_log(fd, buf, (int) strlen(buf));
  271. }
  272.  
  273. /*---------------------------------------------------------------------------*/
  274.  
  275. static int  do_telnet(tp, chr)
  276. struct login_cb *tp;
  277. int  chr;
  278. {
  279.   struct termio termio;
  280.  
  281.   switch (tp->state) {
  282.   case TS_DATA:
  283.     if (chr != IAC) {
  284.       /*** if (!tp->option[TN_TRANSMIT_BINARY]) chr &= 0x7f; ***/
  285.       return 1;
  286.     }
  287.     tp->state = TS_IAC;
  288.     break;
  289.   case TS_IAC:
  290.     switch (chr) {
  291.     case WILL:
  292.       tp->state = TS_WILL;
  293.       break;
  294.     case WONT:
  295.       tp->state = TS_WONT;
  296.       break;
  297.     case DO:
  298.       tp->state = TS_DO;
  299.       break;
  300.     case DONT:
  301.       tp->state = TS_DONT;
  302.       break;
  303.     case IAC:
  304.       tp->state = TS_DATA;
  305.       return 1;
  306.     default:
  307.       tp->state = TS_DATA;
  308.       break;
  309.     }
  310.     break;
  311.   case TS_WILL:
  312.     tp->state = TS_DATA;
  313.     break;
  314.   case TS_WONT:
  315.     tp->state = TS_DATA;
  316.     break;
  317.   case TS_DO:
  318.     if (chr <= NOPTIONS) tp->option[chr] = 1;
  319.     if (chr == TN_ECHO) {
  320.       ioctl(tp->pty, TCGETA, &termio);
  321.       termio.c_lflag |= (ECHO | ECHOE);
  322.       ioctl(tp->pty, TCSETA, &termio);
  323.     }
  324.     tp->state = TS_DATA;
  325.     break;
  326.   case TS_DONT:
  327.     if (chr <= NOPTIONS) tp->option[chr] = 0;
  328.     if (chr == TN_ECHO) {
  329.       ioctl(tp->pty, TCGETA, &termio);
  330.       termio.c_lflag &= ~(ECHO | ECHOE);
  331.       ioctl(tp->pty, TCSETA, &termio);
  332.     }
  333.     tp->state = TS_DATA;
  334.     break;
  335.   }
  336.   return 0;
  337. }
  338.  
  339. /*---------------------------------------------------------------------------*/
  340.  
  341. static void write_pty(tp)
  342. struct login_cb *tp;
  343. {
  344.  
  345.   char  *p;
  346.   char  buf[256];
  347.   int  chr;
  348.   int  cnt;
  349.   int  lastchr;
  350.  
  351.   p = buf;
  352.   while ((chr = PULLCHAR(&tp->sndq)) != -1) {
  353.     lastchr = tp->lastchr;
  354.     tp->lastchr = chr;
  355.     if (!tp->telnet || do_telnet(tp, uchar(chr))) {
  356.       if (lastchr != '\r' || chr != '\0' && chr != '\n') {
  357.     *p++ = chr;
  358.     if (chr == '\r' || chr == '\n') {
  359.       tp->linelen = 0;
  360.       break;
  361.     }
  362.     if (++tp->linelen >= 250) {
  363.       *p++ = '\n';
  364.       tp->linelen = 0;
  365.       break;
  366.     }
  367.       }
  368.     }
  369.   }
  370.   if (cnt = p - buf) {
  371.     write(tp->pty, buf, (unsigned) cnt);
  372.     write_log(tp->pty, buf, cnt);
  373.   }
  374.   if (!tp->sndq) off_write(tp->pty);
  375. }
  376.  
  377. /*---------------------------------------------------------------------------*/
  378.  
  379. static void excp_handler(tp)
  380. struct login_cb *tp;
  381. {
  382.  
  383.     if(is_dead(tp)){
  384.     off_read(tp->pty);
  385.     off_write(tp->pty);
  386.     off_excp(tp->pty);
  387.     if (tp->closefnc) (*tp->closefnc)(tp->fncarg);
  388.     }
  389. }
  390.  
  391. /*---------------------------------------------------------------------------*/
  392.  
  393. struct login_cb *login_open(user, protocol, read_upcall, close_upcall, upcall_arg)
  394. char  *user, *protocol;
  395. void (*read_upcall) __ARGS((void *arg));
  396. void (*close_upcall) __ARGS((void *arg));
  397. void  *upcall_arg;
  398. {
  399.  
  400.   char  *env = 0;
  401.   char  slave[80];
  402.   int  i;
  403.   struct login_cb *tp;
  404.   struct passwd *pw;
  405.   struct termio termio;
  406.   struct utmp utmp;
  407.  
  408.   tp = (struct login_cb *) calloc(1, sizeof(struct login_cb ));
  409.   if (!tp) return 0;
  410.   tp->telnet = !strcmp(protocol, "TELNET");
  411.   if ((tp->pty = find_pty(&tp->num, slave)) < 0) {
  412.     free(tp);
  413.     return 0;
  414.   }
  415.   strcpy(tp->id, slave + strlen(slave) - 2);
  416.   tp->readfnc = read_upcall;
  417.   tp->closefnc = close_upcall;
  418.   tp->fncarg = upcall_arg;
  419.   on_read(tp->pty, tp->readfnc, tp->fncarg);
  420.   on_excp(tp->pty, (void (*)()) excp_handler, tp);
  421.   i = 1;
  422.   write_log_header(tp->pty, user, protocol);
  423.   if (!(tp->pid = fork())) {
  424.     pw = getpasswdentry(user, 1);
  425.     if (!pw || pw->pw_passwd[0]) pw = getpasswdentry("", 0);
  426.     for (i = 0; i < _NFILE; i++) close(i);
  427.     setpgrp();
  428.     open(slave, O_RDWR, 0666);
  429.     dup(0);
  430.     dup(0);
  431.     chmod(slave, 0622);
  432.     memset(&termio, 0, sizeof(termio));
  433.     termio.c_iflag = ICRNL | IXOFF;
  434.     termio.c_oflag = OPOST | ONLCR | TAB3;
  435.     termio.c_cflag = B1200 | CS8 | CREAD | CLOCAL;
  436.     termio.c_lflag = ISIG | ICANON;
  437.     termio.c_cc[VINTR]  = 127;
  438.     termio.c_cc[VQUIT]  =  28;
  439.     termio.c_cc[VERASE] =   8;
  440.     termio.c_cc[VKILL]  =  24;
  441.     termio.c_cc[VEOF]   =   4;
  442.     ioctl(0, TCSETA, &termio);
  443.     ioctl(0, TCFLSH, 2);
  444.     if (!pw || pw->pw_passwd[0]) exit(1);
  445.     memset(&utmp, 0, sizeof(utmp));
  446.     strcpy(utmp.ut_user, "LOGIN");
  447.     strcpy(utmp.ut_id, tp->id);
  448.     strcpy(utmp.ut_line, slave + 5);
  449.     utmp.ut_pid = getpid();
  450.     utmp.ut_type = LOGIN_PROCESS;
  451.     utmp.ut_time = secclock();
  452. #ifdef _UTMP_INCLUDED   /* maybe in a later version of sys5 3.2 or rel 4 ?*/
  453.     strncpy(utmp.ut_host, protocol, sizeof(utmp.ut_host));
  454. #endif
  455.     pututline(&utmp);
  456.     endutent();
  457.     execle("/bin/login", "login", pw->pw_name, (char *) 0, &env);
  458.    exit(1);
  459.   }
  460.   return tp;
  461. }
  462.  
  463. /*---------------------------------------------------------------------------*/
  464.  
  465. void login_close(tp)
  466. struct login_cb *tp;
  467. {
  468.  
  469.   int  fwtmp;
  470.   struct utmp utmp, *up;
  471.  
  472.   if (!tp) return;
  473.   if (tp->pty > 0) {
  474.     off_read(tp->pty);
  475.     off_write(tp->pty);
  476.     off_excp(tp->pty);
  477.     close(tp->pty);
  478.     restore_pty(tp->id);
  479.     pty_inuse[tp->num] = 0;
  480.     write_log(tp->pty, (char *) 0, -1);
  481.   }
  482.   if (tp->pid > 0) {
  483.     kill(-tp->pid, SIGHUP);
  484.     memset(&utmp, 0, sizeof(utmp));
  485.     strcpy(utmp.ut_id, tp->id);
  486.     utmp.ut_type = DEAD_PROCESS;
  487.     if (up = getutid(&utmp)) {
  488.       up->ut_user[0] = '\0';
  489.       up->ut_type = DEAD_PROCESS;
  490.       up->ut_exit.e_termination = 0;
  491.       up->ut_exit.e_exit = 0;
  492.       up->ut_time = secclock();
  493.       memcpy(&utmp, up, sizeof(utmp));
  494.       pututline(up);
  495.       fwtmp = open("/etc/wtmp", O_WRONLY | O_CREAT | O_APPEND, 0644);
  496.       write(fwtmp, (char *) &utmp, sizeof(utmp));
  497.       close(fwtmp);
  498.     }
  499.     endutent();
  500.   }
  501.   free_q(&tp->sndq);
  502.   free(tp);
  503. }
  504.  
  505. /*---------------------------------------------------------------------------*/
  506.  
  507. #define ASIZE 512
  508.  
  509. #define add_to_mbuf(chr) \
  510. { \
  511.   if (!head) head = tail = alloc_mbuf(ASIZE); \
  512.   if (tail->cnt >= ASIZE) tail = tail->next = alloc_mbuf(ASIZE); \
  513.   tail->data[tail->cnt++] = chr; \
  514.   cnt--; \
  515. }
  516.  
  517. /*---------------------------------------------------------------------------*/
  518.  
  519.  
  520. struct mbuf *login_read(tp, cnt)
  521. struct login_cb *tp;
  522. int  cnt;
  523. {
  524.  
  525.   int  chr;
  526.   struct mbuf *head, *tail;
  527.  
  528.   if (cnt <= 0) {
  529.     off_read(tp->pty);
  530.     if(is_dead(tp)){  /* Not every time an exeption, so check it again */
  531.     off_read(tp->pty);
  532.     off_write(tp->pty);
  533.     off_excp(tp->pty);
  534.     if (tp->closefnc) (*tp->closefnc)(tp->fncarg);
  535.    }
  536.     return 0;
  537.   }
  538.   on_read(tp->pty, tp->readfnc, tp->fncarg); 
  539.     if(is_dead(tp)){  /* Not every time an exeption, so check it again */
  540.     off_read(tp->pty);
  541.     off_write(tp->pty);
  542.     off_excp(tp->pty);
  543.     if (tp->closefnc) (*tp->closefnc)(tp->fncarg);
  544.    }
  545.   head = 0;
  546.   while (cnt) {
  547.     if (tp->inpcnt <= 0) {
  548.       if ((tp->inpcnt = read(tp->pty, tp->inpptr = tp->inpbuf, sizeof(tp->inpbuf))) <= 0)
  549.     return head;
  550.       write_log(tp->pty, tp->inpbuf, tp->inpcnt);
  551.     }
  552.     tp->inpcnt--;
  553.     chr = uchar(*tp->inpptr++);
  554.     if (chr == 0x11 || chr == 0x13) {
  555.       /* ignore XON / XOFF */
  556.     } else if (tp->telnet) {
  557.       add_to_mbuf(chr);
  558.       if (chr == IAC) add_to_mbuf(IAC);
  559.     } else {
  560.       if (chr != '\n') add_to_mbuf(chr);
  561.     }
  562.   }
  563.   return head;
  564. }
  565.  
  566. /*---------------------------------------------------------------------------*/
  567.  
  568. void login_write(tp, bp)
  569. struct login_cb *tp;
  570. struct mbuf *bp;
  571. {
  572.   append(&tp->sndq, bp);
  573.   on_write(tp->pty, (void (*)()) write_pty, tp);
  574.   if (tp->linelen) write_pty(tp);
  575. }
  576.  
  577. /*---------------------------------------------------------------------------*/
  578.  
  579. /* check for login process dead */
  580. int
  581. is_dead(tp)
  582.     struct login_cb *tp; {
  583.  
  584.     return kill(tp->pid, 0);
  585. }
  586.